if (!window.org) var org = {};
if (!org.dreamwork) org.dreamwork = {};
if (!org.dreamwork.js) org.dreamwork.js = {};
if (!org.dreamwork.js.ui) org.dreamwork.js.ui = {};

org.dreamwork.js.ui.CellEditor = function () {
	var self = this;
	var component = null;
	var list_map = null;
	var oldValue = null;
	var parent = null;
	var type = arguments [0] || "CustomerType";
    var id = "__" + type + "__Editor__" + (org.dreamwork.js.ui.CellEditor.__COUNT__ ++) + "__";

    // events;
	var click_events = [];
	var key_events = [];
	var editCanceled = [];
	var editStopped = [];

	this.addClickEvent = function (action) {
		if (typeof (action) != 'function') throw "Action must be a function!";
		click_events.push (action);
	}
	this.addKeyEvent = function (action) {
		if (typeof (action) != 'function') throw "Action must be a function!";
		key_events.push (action);
	}
	this.addEditCanceledEvent = function (action) {
		if (typeof action != 'function') throw "Action must be a function!";
		editCanceled.push (action);
	}
	this.addEditStoppedEvent = function (action) {
		if (typeof action != 'function') throw "Action must be a function!";
		editStopped.push (action);
	}

	this.setRenderer = function (renderer) {
		component = renderer;
		component.onclick = function () {
			event.cancelBubble = true;
			for (var i = 0; i < click_events.length; i ++) click_events [i] ();
		}
		saveComponent ();
	}
	this.getRenderer = function () { return component; }
	this.getType = function () { return type; }
    this.getParent = function () { return parent; }
    this.stopEdit = function () {
		if (!parent) return;
		if (!component) return;
        stopEdit ();
		parent = null;
	}

	this.cancelEdit = function () {
		cancelEdit ();
		var event = {src:this, target: parent};
		for (var i = 0; i < editCanceled.length; i ++) editCanceled[i](event);
		parent = null;
	}

	this.install = function (parentElement) {
		if (typeof parentElement != 'object') parentElement = document.getElementById (parentElement);
		var backup = parentElement.onclick;
		parentElement.onclick = function () {
			if (document.currentEditor) document.currentEditor.stopEdit ();
			parent = parentElement;
			if (backup && typeof backup == 'function') backup ();
			showComponent (parentElement);
			component.targetCell = parentElement;
			component.editor = self;
		}
		parentElement.style.cursor = "default";
	}

	this.toString = function () { return type + "Editor [" + id + "]"; }

	if (!document.configed) {
		document.configed = true;
		var backup = document.onclick;
		document.onclick = function () {
			if (backup && typeof (backup) == 'function') backup ();
			if (document.currentEditor) document.currentEditor.stopEdit ();
		}
	}

	if (type == 'text') initTextEditor ();
	else if (type == "list") initListEditor ();
	else if (type == 'bool') initBoolEditor ();

	////////////////////////////////////////////////////////
	// private methods
	////////////////////////////////////////////////////////
	function initTextEditor () {
		var c = document.createElement ("input");
		c.type = "text";
		c.onkeyup = function () {
			if (event.keyCode == 27) cancelEdit ();
			else if (event.keyCode == 13) stopEdit ();
			else for (var i = 0; i < key_events.length; i ++) key_events [i] ();
		}
		self.setRenderer (c);
		self.setValue = function (value) { component.value = value.replace(/&nbsp;/, " "); }
	}

	function initListEditor () {
		var c = document.createElement ("select");
		c.onkeypress = function () { if (event.keyCode == 27) cancelEdit (); }
		self.setRenderer (c);
		self.setValue = function (value) {
			var options = component.options;
			for (var i = 0; i < options.length; i ++) {
				var option = options [i];
				if (option.text == value) { component.selectedIndex = i; break; }
			}
		}
		self.getValue = function () { var options = component.options; return options [component.selectedIndex].text; }
		self.setItems = function (array)  { if (array == undefined) throw "param must be a map"; list_map = array; }
		c.willShown = function () {
			if (c.options.length == 0) for (var value in list_map) {
				var text = list_map [value];
				if (typeof text == 'function') continue;
				var option = document.createElement ("option");
				option.value = value;
				option.text = text;
				c.options [c.options.length ++] = option;
			}
		}
	}

	function initBoolEditor () {
		var c = document.createElement ("input");
		c.type = "checkbox";
		self.setRenderer (c);
		self.setValue = function (value) {
			component.checked = value;
			if (parent) parent.innerHTML = "";
		}
		self.getValue = function () { return component.checked; }
	}

	function getPosition (e) {
		var p = {x:0, y:0, toString: function (){return "[" + this.x + ", " + this.y + "]"}};
		if (e.offsetLeft) p.x += e.offsetLeft;
		if (e.offsetTop)  p.y += e.offsetTop;
		var parentElement = e.offsetParent;
		while (parentElement && parentElement != document.body) {
			if (parentElement.offsetLeft) p.x += parentElement.offsetLeft;
			if (parentElement.offsetTop)  p.y += parentElement.offsetTop;
			p.x -= parentElement.scrollLeft;
			p.y -= parentElement.scrollTop;
			parentElement = parentElement.offsetParent;
		}
		return p;
	}

	function saveComponent () {
		if (document.getElementById (id) == null) {
			component.style.display = "none";
			component.style.position = "absolute";
			component.id = id;
			document.body.appendChild (component);
		}
	}

	function cancelEdit () {
		if (!parent) return;
		parent.innerHTML = oldValue;
		component.value = oldValue;
		component.style.display = "none";
		self.editing = false;
		document.currentEditor = null;
	}

	function stopEdit () {
		switch (type) {
			case "text" :
				if (parent) {
					var text = component.value;
					parent.__editorValue = text;
					parent.innerHTML = text;
					parent.title = text;
				}
				else cancelEdit ();
				break;
			case "list" :
                if (component.selectedIndex >= 0)
					parent.innerHTML = component.options [component.selectedIndex].text;
				else
					cancelEdit ();
				break;
			case "bool" : parent.innerHTML = component.checked ? "true" : "false"; break;
			default :
				parent.innerHTML = component.getValue ();
		}

		var event = {src: self, target: parent};
		for (var i = 0; i < editStopped.length; i ++) editStopped[i](event);

		component.style.display = "none";
		self.editing = false;
		document.currentEditor = null;
	}

	function showComponent (parentElement) {
		if (!component) throw "Renderer is not set!";
		if (!window.event) FixPrototypeForGecko ();
		event.cancelBubble = true;
		oldValue = parentElement.innerHTML;
		self.setValue (oldValue);
		// setup ui
		var p = getPosition (parentElement);
		component.style.left = p.x + "px";
		component.style.top = p.y + "px";
		component.style.width = (parentElement.clientWidth) + "px";
		component.style.height = (parentElement.clientHeight) + "px";
		// copy parent style
		component.style.fontFamily = parentElement.style.fontFamily;
		component.style.fontSize = parentElement.style.fontSize;
		if (component.willShown) component.willShown ();
		// show editor component
		component.style.display = "block";
		if (component.shown) component.shown ();
		try { component.focus (); } catch (ex) {}
		self.editing = true;
		document.currentEditor = self;
	}
}

org.dreamwork.js.ui.CellEditor.__COUNT__ = 0;